![]() |
![]() |
|
Die drei Eigenschaften der Circle-Klasse XKoordinate, YKoordinate und Radius werden nun allesamt durch Eigenschaftsmethoden beschrieben. Da sie Public deklariert sind, können sie von außerhalb der Klasse aufgerufen werden. Die Bezeichner der ursprünglich gleichnamigen Felder sind geändert worden, um innerhalb der Klasse die namentliche Eindeutigkeit zu gewährleisten. Da die Mittelspunktskoordinaten keinen besonderen Anforderungen unterliegen, ist es im vorliegenden Fall vollkommen ausreichend, ohne eine Implementierung des zu übergebenden Wertes direkt an das Feld weiterzureichen bzw. dieses auszuwerten. Der Ersatz der öffentlichen Felder durch eine Kombination von privaten Feldern und öffentlichen Eigenschaftsmethoden kann sich zu einem späteren Zeitpunkt als großer Vorteil herausstellen. Wenn sich die Implementierung des Programmcodes innerhalb der Eigenschaftsmethode als fehlerhaft erweist oder möglicherweise geändert werden muss, wird der aufrufende Code die Änderung nicht bemerken. Er erkennt nur den für ihn sichtbaren, öffentlichen Teil der Schnittstelle, bestehend aus Bezeichner, Parameterliste und Datentyp. Die Implementierungsänderung bleibt ihm verborgen. 4.4.2 Lese- und schreibgeschützte Eigenschaften
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ... |
| Private myVar as Integer |
| Public ReadOnly Property MyProp() As Integer |
| Get |
| Return myVar |
| End Get |
| End Property |
Eine mit ReadOnly gekennzeichnete, schreibgeschützte Eigenschaft macht natürlich keinen Sinn, wenn es keinen anderen Weg geben würde, ihr einen Wert zuzuweisen. Dieser Weg führt in der Regel über den Aufruf einer anderen Methode der Klasse, die ihrerseits den Wert nach einem vorgegebenen Algorithmus setzt. Oftmals werden gekapselte Felder von schreibgeschützten Eigenschaften auch bei der Initialisierung des Objekts in einem parametrisierten Konstruktor festgelegt.
Soll eine Objekteigenschaft zur Laufzeit einer Anwendung lesegeschützt sein, wird in der Definition der Eigenschaft das Schlüsselwort WriteOnly angegeben. Eine lesegeschützte Eigenschaft darf nur den Set-Accessor enthalten.
| Public WriteOnly Property MyProp() As Integer |
| Set(ByVal Value As Integer) |
| myVar = Value |
| End Set |
| End Property |
Da die Rückgabe einer lesegeschützten Eigenschaft vorgesehen ist, bleibt der Inhalt des privaten Feldes dem Aufrufer verborgen. Die Eingabe eines Passwortes, das dazu benutzt wird, benutzerabhängige Zugriffe auf das Objekt methodenabhängig zu steuern, ist dafür ein typisches Beispiel.
Der Wert einer lesegeschützten Eigenschaft kann selbstverständlich durch eine andere Instanzmethode zurückgegeben werden.
Wird keine andere Angabe gemacht, entspricht die Sichtbarkeit der beiden Accessoren Get und Set per Vorgabe der Sichtbarkeit der Eigenschaftsmethode. Ist die Eigenschaftsmethode beispielsweise Public, sind Get und Set automatisch ebenfalls ohne Einschränkung sichtbar. Mit einem neuen Feature wartet VB 2005 auf: Die Accessoren dürfen eine individuelle Sichtbarkeit aufweisen. Damit lässt sich der Zugriff auf die beiden Accessoren feiner steuern.
| Public Property TestProperty() As Integer |
| Set(ByVal value As Integer) |
| someValue = value |
| End Set |
| Friend Get |
| Return someValue |
| End Get |
| End Property |
In diesem Codefragment ist die Eigenschaft TestProperty öffentlich definiert. Der Set-Accessor hat keinen abweichenden Zugriffsmodifizierer, folglich kann aus jeder anderen Anwendung heraus der Wert gesetzt werden. Im Gegensatz dazu schränkt der Zugriffsmodifizierer Friend das Auswerten der Eigenschaft auf die aktuelle Anwendung ein. Code, der sich nicht in der gleichen Anwendung befindet, kann den Inhalt des Feldes someValue nicht auswerten.
Der Einsatz der Zugriffsmodifizierer auf die beiden Accessoren unterliegt Regeln, die Sie sich merken sollten:
| In der Eigenschaftsmethode müssen beide Accessoren definiert sein. |
| Nur bei einem der beiden Accessoren darf ein vom Zugriffsmodifizierer der Eigenschaftsmethode abweichender Zugriffsmodifizierer angegeben werden. |
| Der Zugriffsmodifizierer des Accessors muss einschränkender sein als der der Eigenschaftsmethode. Angenommen die Eigenschaftsmethode ist Public definiert, so können die Modifizierer Friend, Protected und Private benutzt werden. Public wäre in diesem Fall sogar unzulässig. |
Stellen Sie sich vor, Sie hätten die Klasse Car mit der Eigenschaft Farbe als Komponente einer größeren Anwendung definiert, die von einem Autohändler einer bestimmten Marke eingesetzt wird. Wie Ihnen sicherlich bekannt ist, hängt die angebotene Außenfarbe eines Wagens oft von der Ausstattung eines Typs ab. Bestellen Sie die Version GTI, können Sie möglicherweise nur aus der ansonsten reichhaltigeren Farbpalette Schwarz oder Rot wählen, bei der Version SDI darüber hinaus noch Gelb und Silbermetallic.
Wie aber kann diese Abhängigkeit einer Klassendefinition mitgeteilt werden? Müssen Sie für jede Ausstattungsvariante eine neue Klasse implementieren, oder bieten sich andere Möglichkeiten an?
Es gibt andere Möglichkeiten. Sie können die Parameterliste der Eigenschaftsmethode dazu benutzen, die Farbwahl abhängig vom gewählten Typ zu überprüfen. Dazu wird bei der Zuweisung der Farbe an das Car-Objekt als Argument der Typ angegeben.
| mycar.Farbe("GTI") = Rot |
Es sei davon ausgegangen, dass den Farben Integer-Konstanten zugeordnet sind. Die zu diesem Aufruf zugehörige Definition der Property-Prozedur würde in diesem speziellen Fall wie folgt lauten:
| Public Class Car |
| 'gekapselte Instanzvariable |
| Private autoFarbe As Int32 |
| Public Property Farbe(ByVal type As String) As Integer |
| ... |
| Set(ByVal Value As Integer) |
| Select Case type |
| Case "GTI" |
| Select Case Value |
| Case 1, 2 |
| autoFarbe = Value |
| Case Else |
| Console.WriteLine("Unzulässige Farbe") |
| End Select |
| Case "SDI" |
| Select Case Value |
| Case 1, 2, 3, 5, 8, 9 |
| autoFarbe = Value |
| Case Else |
| Console.WriteLine("Unzulässige Farbe") |
| End Select |
| End Select |
| End Set |
| End Property |
| End Class |
Sie können die Parameterliste auch dazu benutzen, mehrere Zustandswerte mit einem Aufruf dem Objekt mitzuteilen. Bezogen auf das Beispiel wäre es demnach möglich, neben dem Farbwert auch in einem Aufruf die Ausstattungsvariante des gewählten Typs festzulegen.
Ein kleiner Hinweis ist an dieser Stelle angebracht. Der Zusammenhang zwischen der Ausstattungsvariante und den angebotenen Farben ist offensichtlich. Sollten Sie auf eine ähnliche Problematik stoßen, wäre es überlegenswert, die Abhängigkeiten durch eine Datenbank abzubilden. Da das Beispiel nur als eine Demonstration des Einsatzes der Parameterliste dient, haben wir auf eine genaue Analyse zur Findung der besten Lösung verzichtet.
Sie werden wahrscheinlich nur sehr selten eine Eigenschaft mit einer Parameterliste definieren müssen. Sinnvoll ist eine Parameterliste meist nur dann, wenn beim Setzen einer Instanzvariablen Randbedingungen von Interesse sind, die einen Einfluss auf den endgültigen Inhalt des Feldes haben.
Eine Standardeigenschaft kann auf eine Objektreferenz aufgerufen werden, ohne die Eigenschaft ausdrücklich anzugeben. Voraussetzung ist, dass in der Parameterliste der Eigenschaftsmethode zumindest ein nichtoptionaler Parameter angegeben ist. Das alleine ist allerdings noch nicht ausreichend, zusätzlich muss der Methodensignatur mit Default noch ein weiterer Modifizierer hinzugefügt werden.
Betrachten Sie das folgende Codefragment einer Standardeigenschaft, die diese beiden Bedingungen erfüllt:
| Public Class MyOwnClass |
| Private intVar As Integer |
| Default Public Property MyProp(ByVal x As Long) As Integer |
| Get |
| Return intVar |
| End Get |
| Set(ByVal Value As Integer) |
| intVar = Value |
| End Set |
| End Property |
| End Class |
Die Eigenschaft MyProp kann nun auf zweierlei Weise aufgerufen werden. Zunächst einmal bietet sich der herkömmliche Weg über die explizite Angabe des Eigenschaftsnamens an, also:
| Dim obj As New MyOwnClass() |
| obj.MyProp(15) = 2 |
Wegen der Inanspruchnahme der Standardeigenschaft wäre die kürzere, aber sicherlich auch schlechter lesbare und daher auch weniger empfehlenswerte Variante:
| Dim obj As New MyOwnClass() |
| obj(15) = 2 |
Was auffällt, ist die syntaktische Ähnlichkeit mit der Zuweisung an ein Array-Element, was durchaus zu Verwechslungen führen kann. Interessant wird es aber insbesondere dann, wenn tatsächlich ein Objekt-Array dieses Typs deklariert und der Standardeigenschaft eines Elements dieses Arrays ein Wert zugewiesen wird.
| Sub Main() |
| Dim obj(3) As MyOwnClass |
| obj(1) = New MyOwnClass() |
| obj(1)(2) = 9 |
| Console.WriteLine(obj(1)(2)) |
| Console.Read() |
| End Sub |
Zunächst wird das dynamische Objektfeld obj mit vier Elementen deklariert. Jedes Element eines Objekt-Arrays muss einzeln initialisiert werden – im Beispiel oben ist es das zweite Element mit dem Index 1, dessen Standardeigenschaft in der darauf folgenden Codezeile ohne explizite Angabe des Feldnamens MyProp ein Wert zugewiesen wird.
| obj(1)(2) = 9 |
Es lässt sich kaum darüber streiten, ob die Zuweisung in die Kategorie gute Lesbarkeit fällt oder nicht. Welcher der beiden Klammerwerte repräsentiert den Array-Index des Elements, welcher ist das der Parameterliste übergebene Argument? Besser wäre es, die Eigenschaft explizit zu nennen:
| obj(1).MyProp(2) = 9 |
Sie sollten sich daher sehr genau überlegen, ob Sie eine Eigenschaft zu einer Standardeigenschaft erklären.
Sie werden sehr oft in die Situation kommen, auf die Eigenschaften oder Methoden eines Objekts mehrfach hintereinander zugreifen zu müssen. Es kann dabei recht mühevoll werden, immer wieder den Bezeichner neu eingeben zu müssen.
Visual Basic bietet mit dem With ... End With-Statement eine recht attraktive Möglichkeit, sowohl die Tipparbeit zu verkürzen als auch den Programmcode übersichtlicher zu gestalten. Die Syntax hierzu lautet:
| With <Objektbezeichner> |
| [Statement 1] |
| [Statement 2] |
| ... |
| [Statement 3] |
| End With |
Schauen wir uns den Einsatz an einem kleinen Beispiel an, bei dem wir wieder die Existenz einer Klasse Car annehmen:
| Dim meinAuto As New Car() |
| With meinAuto |
| .Farbe = 10 |
| .Hersteller = "Audi" |
| Console.WriteLine("Kaufpreis = {0}", .Kaufpreis) |
| .Fahren() |
| End With |
Es werden mehrere Statements auf ein Objekt ausgeführt, ohne die qualifizierende Referenz anzugeben. Die Punktnotation wird vor dem Punkt aufgebrochen, der nun vor der Angabe einer Elementfunktion geschrieben werden muss, um die Zugehörigkeit der Elementfunktion kenntlich zu machen. Dabei spielt es keine Rolle, ob es sich bei der Elementfunktion um eine Eigenschaft oder Methode handelt.
With ... End With-Statements können auch verschachtelt werden. Dieser Fall setzt eine zumindest zweifach auftretende Punktnotation voraus, die dann auftritt, wenn eine Objekteigenschaft ihrerseits selbst wieder durch ein anderes Objekt beschrieben wird.
| With Form1 |
| .Height = 1000 |
| .Width = 2500 |
| With .Font |
| 'entspricht Form1.Font.Italic = False |
| .Italic = False |
| .Bold = True |
| End With |
| End With |
Eine diametrale Verschachtelung ist nicht zulässig.
Das With ... End With-Statement unterliegt einer Einschränkung: Es darf nur auf Objekte angewandt werden.
Sie könnten die öffentliche Variable einer Klasse mit ReadOnly schreibgeschützt implementieren:
| Public ReadOnly MyConst As Integer = 12 |
Ein zweite Alternative bietet das Schlüsselwort Const.
| Public Const MyConst As Integer = 12 |
Was im ersten Moment identisch aussieht, birgt dennoch einen kleinen Unterschied. Der Wert einer als Const definierten Konstanten kann zu keinem Zeitpunkt der Laufzeit verändert werden.
Etwas weniger restriktiv verhalten sich ReadOnly-Konstanten, denn deren Wert kann tatsächlich noch geändert werden. Allerdings beschränkt sich der Zeitpunkt der möglichen Änderung auf die Ausführung eines Konstruktors, der bei jeder Objektinstanziierung aufgerufen wird (Konstruktoren behandeln wir weiter unter in diesem Kapitel).
| Public Sub New() |
| MyConst = 34 |
| End Sub |
Wenn das Objekt vollständig erstellt ist, ist eine Änderung der ReadOnly-Konstanten nicht mehr erlaubt.
Eine Objektmethode kann nicht auf die privaten Daten eines anderen Objekts zugreifen. Dies war bisher immer die Aussage, die allerdings nicht uneingeschränkt gültig ist, wie das folgende Beispiel der Klasse TestClass zeigen soll.
| Class TestClass |
| Private intVar As Integer |
| Public Sub InternProc(ByVal obj As TestClass) |
| Console.Write("intVar des Objekts = {0}", obj.intVar) |
| End Sub |
| Public Property MyValue() As Integer |
| Get |
| Return intVar |
| End Get |
| Set(ByVal value As Integer) |
| intVar = value |
| End Set |
| End Property |
| End Class |
In der Klassendefinition ist das Feld intVar Private deklariert, um den unbefugten, direkten Zugriff von außen zu unterbinden. Dieses Feld kann infolgedessen nur durch eine Eigenschaft manipuliert werden, in unserem Beispiel MyValue.
Mit etwas Besonderem wartet die Methode InternProc auf. Sie empfängt beim Aufruf im Parameter obj die Referenz auf ein anderes Objekt vom Typ TestClass. Es mag überraschend klingen, aber diese Referenz soll dazu benutzt werden, um auf die private Instanzvariable intVar des übergebenen Objekts zuzugreifen. Nach allen bisherigen Aussagen dürfte dieser Zugriff eigentlich nicht erlaubt sein.
Im folgenden Codefragment wollen wir die Klasse TestClass testen. Dazu werden zwei konkrete Objekte vom Typ TestClass erzeugt und der Eigenschaft MyValue des ersteren ein Wert zugewiesen.
| Dim obj1 As New TestClass |
| Dim obj2 As New TestClass |
| obj1.MyValue = 4711 |
Im nächsten Schritt folgt der Aufruf der InternProc-Methode des Objekts obj2 unter Übergabe der Referenz auf das Objekt obj1.
| obj2.InternProc(obj1) |
Tatsächlich wird an der Konsole der Inhalt der gekapselten, privaten Instanzvariablen angezeigt:
| intVar des Objekts = 4711 |
Die Kapselung der Variablen wird also aufgebrochen, die Variable ist auswertbar. Dieser Effekt scheint im Widerspruch zu dem zu stehen, was Sie bisher über die Kapselung gehört haben, und bildet die einzige Ausnahme, die der folgende Satz beschreibt:
|
Aus einem Objekt heraus kann auf private Instanzvariablen eines anderen Objekts zugegriffen werden, wenn beide Objekte vom gleichen Typ sind. |
| Zustandsdaten eines Objekts werden in Feldern vorgehalten. Ist ein Feld Public deklariert, gehört es zur öffentlichen Schnittstelle eines Objekts und kann ohne Einschränkungen von außen manipuliert werden. |
| Ein Private deklariertes Feld kapselt den von ihm beschriebenen Wert. Der Wert kann nur von Code, der sich innerhalb der Klasse befindet, manipuliert werden. |
| Standardmäßig enthält eine Eigenschaftsmethode die beiden Accessoren Get und Set, die jeweils einen eigenen Anweisungsblock beschreiben. Der Get-Block wird ausgeführt, wenn ein externer Aufrufer ein bestimmtes Feld auswerten möchte, der Set-Block wird bei der Zuweisung an ein Feld aufgerufen. |
| Fehlt in einer Eigenschaft der Set-Accessor, handelt es sich um eine schreibgeschützte Eigenschaft, fehlt der Get-Accessor, ist die Eigenschaft lesegeschützt. Eine schreibgeschützte Methode wird um den Modifizierer ReadOnly ergänzt, eine lesegeschützte um WriteOnly. |
| Einer der beiden Accessoren kann eine von der Eigenschaftsmethode abweichende Sichtbarkeit haben. Dazu wird dem Accessor ein Zugriffsmodifizierer vorangestellt, der einschränkender sein muss als der der Eigenschaftsmethode. |
| Konstanten werden im Deklarationsabschnitt einer Klasse festgelegt. Sie ähneln einer Felddefinition, ergänzt um das Schlüsselwort Const und den von ihnen repräsentierten Wert. |
| Eine Konstante kann auch mit dem Schlüsselwort ReadOnly definiert werden. Die Zuweisung an ein ReadOnly-Feld muss nicht in der Deklarationsanweisung stehen, sondern kann auch in einem Konstruktor erfolgen. |
| Aus einem Objekt heraus kann auf private Instanzvariablen eines anderen Objekts zugegriffen werden – vorausgesetzt, beide Objekte sind vom gleichen Typ. |
| << zurück |
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken.
Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die
gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich
geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung,
Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.